#pragma once
#include <functional>
#include <sstream>
#include "mysql.hpp"
#include "user.hxx"
#include "user-odb.hxx"


// 用户注册，用户登录，验证码获取，手机号注册，手机号登录，获取用户信息
// 用户信息新增，通过昵称获取用户信息，通过手机号获取用户信息，通过用户ID获取用户信息，通过多个用户ID获取多个用户信息，信息修改

namespace suye
{
class UserTable {
public:
    using ptr = std::shared_ptr<UserTable>;
    UserTable(const std::shared_ptr<odb::core::database>& db): _db(db) {}

    bool insert(const std::shared_ptr<User>& user,
                const std::function<bool()>& in_tx_hook = nullptr) 
    {
        try {
            odb::transaction trans(_db->begin());
            _db->persist(*user);
            if (in_tx_hook) {
                if (!in_tx_hook()) {
                    LOG_ERROR("新增用户失败：Outbox 事件写入失败-{}！", user->user_id());
                    trans.rollback();
                    return false;
                }
            }
            trans.commit();
        } catch(std::exception &e) {
            LOG_ERROR("新增用户失败：{}-{}！", user->nickname(), e.what());
            return false;
        }
        return true;
    }

    bool update(const std::shared_ptr<User>& user,
                const std::function<bool()>& in_tx_hook = nullptr) 
    {
        try {
            odb::transaction trans(_db->begin());
            _db->update(*user);
            if (in_tx_hook) {
                if (!in_tx_hook()) {
                    LOG_ERROR("更新用户失败：Outbox 事件写入失败-{}！", user->user_id());
                    trans.rollback();
                    return false;
                }
            }
            trans.commit();
        } catch(std::exception &e) {
            LOG_ERROR("更新用户失败：{}-{}！", user->nickname(), e.what());
            return false;
        }
        return true;
    }

    std::shared_ptr<User> select_by_nickname(const std::string& nickname) 
    {
        std::shared_ptr<User> res;
        try {
            //获取事务对象开启事务
            odb::transaction trans(_db->begin());
            typedef odb::query<User> query;
            res.reset(_db->query_one<User>(query::nickname == nickname));
            // 提交事务
            trans.commit();
        } catch(std::exception &e) {
            LOG_ERROR("通过昵称查询用户失败：{}-{}！", nickname, e.what());
        }
        return res;
    }

    std::shared_ptr<User> select_by_phone(const std::string& phone) 
    {
        std::shared_ptr<User> res;
        try {
            //获取事务对象开启事务
            odb::transaction trans(_db->begin());
            typedef odb::query<User> query;
            res.reset(_db->query_one<User>(query::phone == phone));
            // 提交事务
            trans.commit();
        } catch(std::exception &e) {
            LOG_ERROR("通过手机号查询用户失败：{}-{}！", phone, e.what());
        }
        return res;
    }

    std::shared_ptr<User> select_by_uid(const std::string& user_id) 
    {
        std::shared_ptr<User> res;
        try {
            //获取事务对象开启事务
            odb::transaction trans(_db->begin());
            typedef odb::query<User> query;
            res.reset(_db->query_one<User>(query::user_id == user_id));
            // 提交事务
            trans.commit();
        } catch(std::exception &e) {
            LOG_ERROR("通过用户ID查询用户失败：{}-{}！", user_id, e.what());
        }
        return res;
    }

    std::vector<User> select_by_multi_users(const std::vector<std::string>& id_list)
    {
        // select * from user where id in ('id1', 'id2', ...)
        if (id_list.empty()) {
            return std::vector<User>();
        }
        std::vector<User> res;
        try {
            //获取事务对象开启事务
            odb::transaction trans(_db->begin());
            typedef odb::query<User> query;
            typedef odb::result<User> result;
            std::stringstream ss;
            ss << "user_id in (";
            for (const auto& id: id_list) {
                ss << "'" << id << "',";
            }
            std::string condition = ss.str();
            condition.pop_back();
            condition += ")";
            result r(_db->query<User>(condition));
            for (auto it = r.begin(); it != r.end(); ++it) {
                res.push_back(*it);
            }
            // 提交事务
            trans.commit();
        } catch(std::exception &e) {
            LOG_ERROR("通过用户ID批量查询用户失败：{}！", e.what());
        }
        return res;
    }

private:
    std::shared_ptr<odb::core::database> _db;
};
}
